#pragma once
#include <time.h>
#include <cstdio>
#include <sstream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
#include <iostream>
#include <random>
#include <chrono>
#include <iomanip> 
#include <atomic>

namespace RPC
{

#define _DEBUG 0
#define _INFO 1
#define _ERROR 2
#define DEFAULT_LEVEL 1

#define LOG(levelstr, level, format, ...)                                                    \
    {                                                                                        \
        if (level >= DEFAULT_LEVEL)                                                          \
        {                                                                                    \
            time_t timestamp = time(0);                                                      \
            tm *cur_time = localtime(&timestamp);                                            \
            printf("[%d_%d_%d %d:%d:%d|%s:%d]"                                               \
                   "["                                                                       \
                   "%s"                                                                      \
                   "]"                                                                       \
                   ": " format "\n",                                                         \
                   cur_time->tm_year + 1900, cur_time->tm_mon + 1,                           \
                   cur_time->tm_mday, cur_time->tm_hour, cur_time->tm_min, cur_time->tm_sec, \
                   __FILE__, __LINE__, levelstr, ##__VA_ARGS__);                             \
        }                                                                                    \
    }

#define INFO_LOG(format, ...) LOG("INFO", _INFO, format, ##__VA_ARGS__)
#define DEBUG_LOG(format, ...) LOG("DEBUG", _DEBUG, format, ##__VA_ARGS__)
#define ERROR_LOG(format, ...) LOG("ERROR", _ERROR, format, ##__VA_ARGS__)

    class JSON
    {
        public:
        bool static serialize(Json::Value &root, std::string &jsonStr)
        {
            std::stringstream ss;
            Json::StreamWriterBuilder builter;
            std::unique_ptr<Json::StreamWriter> writer(builter.newStreamWriter());
            int ret = writer->write(root, &ss);
            if (ret)
            {
                ERROR_LOG("%s", "serialize failed");
                return false;
            }
            jsonStr = ss.str();
            return true;
        }

        bool static deserialize(const std::string &jsonStr, Json::Value &root)
        {
            Json::CharReaderBuilder builder;
            std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
            std::string errs;
            int ret = reader->parse(jsonStr.c_str(), jsonStr.c_str() + jsonStr.size(),
                                    &root, &errs);
            if (!ret)
            {
                ERROR_LOG("%s", "deserialize failed");
                return false;
            }
            // std::cout << "errs: " << errs << std::endl;
            return true;
        }
    };

    class UUID
    {
    public:
        static std::string uuid()
        {
            std::stringstream ss;
            // 1、创建机器随机数对象
            std::random_device rd;
            // 2、利用机器随机数创建随机生成随机数对象
            std::mt19937 rand_generator(rd());
            // 3、生成控制随机数生成范围对象。
            std::uniform_int_distribution<int> distribution(0, 255);

            for (int i = 0; i < 8; i++)
            {
                if (i == 4 || i == 6)
                    ss << "-";
                ss << std::setw(2) << std::setfill('0') << std::hex << distribution(rand_generator);
            }
            // DEBUG_LOG("%s", ss.str().c_str());
            // DEBUG_LOG("%s", "hello");
            static std::atomic<size_t> count(0);
            count.fetch_add(1);
            ss << "-";
            for (int i = 7; i >= 0; i--)
            {
                if (i == 5)
                    ss << "-";
                ss << std::setw(2) << std::setfill('0') << std::hex << ((count >> 8 * i) & 0xff);
            }
            // DEBUG_LOG("%s", ss.str().c_str());

            return ss.str();
        }
    };
}
